#!/bin/bash # Test Timer Echo Happy Path (Docker Environment) # Verifies the complete event flow with unified runtime detection set -e # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Configuration API_URL="${ATTUNE_API_URL:-http://localhost:8080}" API_USER="${ATTUNE_API_USER:-admin}" API_PASSWORD="${ATTUNE_API_PASSWORD:-admin}" WAIT_TIME=15 # Time to wait for executions POLL_INTERVAL=2 # How often to check for executions echo -e "${BLUE}=== Attune Timer Echo Happy Path Test (Docker) ===${NC}" echo "API URL: $API_URL" echo "" # Function to print colored status print_status() { echo -e "${GREEN}✓${NC} $1" } print_error() { echo -e "${RED}✗${NC} $1" } print_info() { echo -e "${YELLOW}ℹ${NC} $1" } # Function to check if a service is healthy check_service() { local service=$1 if docker ps --format '{{.Names}}' | grep -q "^${service}$"; then if docker ps --filter "name=${service}" --filter "health=healthy" --format '{{.Names}}' | grep -q "^${service}$"; then print_status "Service $service is healthy" return 0 else print_error "Service $service is not healthy yet" return 1 fi else print_error "Service $service is not running" return 1 fi } # Step 0: Check Docker services echo -e "${BLUE}Step 0: Checking Docker services...${NC}" SERVICES=("attune-api" "attune-executor" "attune-worker" "attune-sensor" "postgres" "rabbitmq") ALL_HEALTHY=true for service in "${SERVICES[@]}"; do if ! check_service "$service" 2>/dev/null; then ALL_HEALTHY=false print_info "Service $service not ready yet" fi done if [ "$ALL_HEALTHY" = false ]; then print_info "Some services are not ready. Waiting 10 seconds..." sleep 10 fi echo "" # Step 1: Login and get JWT token echo -e "${BLUE}Step 1: Authenticating...${NC}" LOGIN_RESPONSE=$(curl -s -X POST "$API_URL/auth/login" \ -H "Content-Type: application/json" \ -d "{\"username\":\"$API_USER\",\"password\":\"$API_PASSWORD\"}") ACCESS_TOKEN=$(echo "$LOGIN_RESPONSE" | jq -r '.data.access_token // empty') if [ -z "$ACCESS_TOKEN" ]; then print_error "Failed to authenticate" echo "Response: $LOGIN_RESPONSE" exit 1 fi print_status "Authentication successful" echo "" # Step 2: Verify runtime detection echo -e "${BLUE}Step 2: Verifying runtime detection...${NC}" RUNTIMES_RESPONSE=$(curl -s -X GET "$API_URL/api/v1/runtimes" \ -H "Authorization: Bearer $ACCESS_TOKEN") SHELL_RUNTIME=$(echo "$RUNTIMES_RESPONSE" | jq -r '.data[] | select(.name == "shell" or .name == "Shell") | .name') if [ -n "$SHELL_RUNTIME" ]; then print_status "Shell runtime detected: $SHELL_RUNTIME" # Get runtime details RUNTIME_DETAILS=$(echo "$RUNTIMES_RESPONSE" | jq -r ".data[] | select(.name == \"$SHELL_RUNTIME\")") echo "$RUNTIME_DETAILS" | jq '{name, enabled, distributions}' || echo "$RUNTIME_DETAILS" else print_error "Shell runtime not found" echo "Available runtimes:" echo "$RUNTIMES_RESPONSE" | jq '.data[] | {name, enabled}' exit 1 fi echo "" # Step 3: Check if core pack exists echo -e "${BLUE}Step 3: Checking for core pack...${NC}" PACK_RESPONSE=$(curl -s -X GET "$API_URL/api/v1/packs/core" \ -H "Authorization: Bearer $ACCESS_TOKEN") PACK_ID=$(echo "$PACK_RESPONSE" | jq -r '.data.id // empty') if [ -z "$PACK_ID" ]; then print_error "Core pack not found" print_info "Attempting to load core pack..." # Try to load core pack via docker exec if docker ps --format '{{.Names}}' | grep -q "^attune-api$"; then docker exec attune-api /opt/attune/scripts/load-core-pack.sh || true sleep 2 # Retry PACK_RESPONSE=$(curl -s -X GET "$API_URL/api/v1/packs/core" \ -H "Authorization: Bearer $ACCESS_TOKEN") PACK_ID=$(echo "$PACK_RESPONSE" | jq -r '.data.id // empty') if [ -z "$PACK_ID" ]; then print_error "Failed to load core pack" exit 1 fi else print_error "Cannot load core pack - API container not accessible" exit 1 fi fi print_status "Core pack found (ID: $PACK_ID)" echo "" # Step 4: Check interval timer trigger echo -e "${BLUE}Step 4: Checking for interval timer trigger...${NC}" TRIGGERS_RESPONSE=$(curl -s -X GET "$API_URL/api/v1/triggers" \ -H "Authorization: Bearer $ACCESS_TOKEN") INTERVAL_TRIGGER=$(echo "$TRIGGERS_RESPONSE" | jq -r '.data[] | select(.ref == "core.intervaltimer") | .ref') if [ -z "$INTERVAL_TRIGGER" ]; then print_error "Interval timer trigger not found" echo "Available triggers:" echo "$TRIGGERS_RESPONSE" | jq '.data[] | {ref, name}' exit 1 fi print_status "Interval timer trigger found" echo "" # Step 5: Check echo action echo -e "${BLUE}Step 5: Checking for echo action...${NC}" ACTIONS_RESPONSE=$(curl -s -X GET "$API_URL/api/v1/actions" \ -H "Authorization: Bearer $ACCESS_TOKEN") ECHO_ACTION=$(echo "$ACTIONS_RESPONSE" | jq -r '.data[] | select(.ref == "core.echo") | .ref') if [ -z "$ECHO_ACTION" ]; then print_error "Echo action not found" echo "Available actions:" echo "$ACTIONS_RESPONSE" | jq '.data[] | {ref, name, runtime}' exit 1 fi print_status "Echo action found" ACTION_DETAILS=$(echo "$ACTIONS_RESPONSE" | jq -r '.data[] | select(.ref == "core.echo")') echo "$ACTION_DETAILS" | jq '{ref, name, runtime, entry_point}' echo "" # Step 6: Create trigger instance for 1-second interval echo -e "${BLUE}Step 6: Creating trigger instance...${NC}" TRIGGER_INSTANCE_REF="test.timer_1s_$(date +%s)" CREATE_TRIGGER_RESPONSE=$(curl -s -X POST "$API_URL/api/v1/trigger-instances" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d "{ \"trigger_type_ref\": \"core.intervaltimer\", \"ref\": \"$TRIGGER_INSTANCE_REF\", \"description\": \"Test timer - 1 second interval\", \"enabled\": true, \"parameters\": { \"unit\": \"seconds\", \"interval\": 1 } }") TRIGGER_INSTANCE_ID=$(echo "$CREATE_TRIGGER_RESPONSE" | jq -r '.data.id // empty') if [ -z "$TRIGGER_INSTANCE_ID" ]; then print_error "Failed to create trigger instance" echo "Response: $CREATE_TRIGGER_RESPONSE" exit 1 fi print_status "Trigger instance created (ID: $TRIGGER_INSTANCE_ID, Ref: $TRIGGER_INSTANCE_REF)" echo "" # Step 7: Create rule linking timer to echo echo -e "${BLUE}Step 7: Creating rule...${NC}" RULE_REF="test.timer_echo_1s_$(date +%s)" CREATE_RULE_RESPONSE=$(curl -s -X POST "$API_URL/api/v1/rules" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d "{ \"ref\": \"$RULE_REF\", \"pack_ref\": \"core\", \"name\": \"Test Timer Echo 1s\", \"description\": \"Test rule - echoes Hello World every second\", \"enabled\": true, \"trigger_instance_ref\": \"$TRIGGER_INSTANCE_REF\", \"action_ref\": \"core.echo\", \"action_parameters\": { \"message\": \"Hello, World! (from unified runtime detection test)\" } }") RULE_ID=$(echo "$CREATE_RULE_RESPONSE" | jq -r '.data.id // empty') if [ -z "$RULE_ID" ]; then print_error "Failed to create rule" echo "Response: $CREATE_RULE_RESPONSE" exit 1 fi print_status "Rule created (ID: $RULE_ID, Ref: $RULE_REF)" echo "" # Step 8: Wait for executions echo -e "${BLUE}Step 8: Waiting for executions...${NC}" print_info "Waiting $WAIT_TIME seconds for timer to fire and action to execute..." EXECUTION_COUNT=0 START_TIME=$(date +%s) MAX_WAIT=$((START_TIME + WAIT_TIME)) while [ $(date +%s) -lt $MAX_WAIT ]; do sleep $POLL_INTERVAL # Check for executions EXECUTIONS_RESPONSE=$(curl -s -X GET "$API_URL/api/v1/executions?limit=50" \ -H "Authorization: Bearer $ACCESS_TOKEN") CURRENT_COUNT=$(echo "$EXECUTIONS_RESPONSE" | jq '[.data[] | select(.action_ref == "core.echo")] | length') if [ "$CURRENT_COUNT" -gt "$EXECUTION_COUNT" ]; then EXECUTION_COUNT=$CURRENT_COUNT ELAPSED=$(($(date +%s) - START_TIME)) print_status "Found $EXECUTION_COUNT execution(s) after ${ELAPSED}s" fi done echo "" # Step 9: Verify executions echo -e "${BLUE}Step 9: Verifying executions...${NC}" if [ "$EXECUTION_COUNT" -eq 0 ]; then print_error "No executions found!" print_info "Checking system status..." # Check for events EVENTS_RESPONSE=$(curl -s -X GET "$API_URL/api/v1/events?limit=10" \ -H "Authorization: Bearer $ACCESS_TOKEN") EVENT_COUNT=$(echo "$EVENTS_RESPONSE" | jq '.data | length') echo " Events created: $EVENT_COUNT" # Check for enforcements ENFORCEMENTS_RESPONSE=$(curl -s -X GET "$API_URL/api/v1/enforcements?limit=10" \ -H "Authorization: Bearer $ACCESS_TOKEN") ENFORCEMENT_COUNT=$(echo "$ENFORCEMENTS_RESPONSE" | jq '.data | length') echo " Enforcements created: $ENFORCEMENT_COUNT" print_error "Happy path test FAILED - no executions" exit 1 fi print_status "Found $EXECUTION_COUNT execution(s)" # Get execution details EXECUTIONS_RESPONSE=$(curl -s -X GET "$API_URL/api/v1/executions?limit=5" \ -H "Authorization: Bearer $ACCESS_TOKEN") echo "" echo "Recent executions:" echo "$EXECUTIONS_RESPONSE" | jq '.data[] | select(.action_ref == "core.echo") | {id, status, action_ref, result: .result.stdout // .result}' | head -20 # Check for successful executions SUCCESS_COUNT=$(echo "$EXECUTIONS_RESPONSE" | jq '[.data[] | select(.action_ref == "core.echo" and .status == "succeeded")] | length') if [ "$SUCCESS_COUNT" -gt 0 ]; then print_status "$SUCCESS_COUNT execution(s) succeeded" else print_error "No successful executions found" echo "" echo "Execution statuses:" echo "$EXECUTIONS_RESPONSE" | jq '.data[] | {id, status, action_ref}' fi echo "" # Step 10: Check worker logs for runtime detection echo -e "${BLUE}Step 10: Checking worker logs for runtime execution...${NC}" if docker ps --format '{{.Names}}' | grep -q "^attune-worker$"; then print_info "Recent worker logs:" docker logs attune-worker --tail 30 | grep -i "runtime\|shell\|echo\|executing" || echo " (no matching log entries)" else print_info "Worker container not accessible for log inspection" fi echo "" # Step 11: Cleanup echo -e "${BLUE}Step 11: Cleanup...${NC}" # Disable the rule print_info "Disabling rule..." curl -s -X PUT "$API_URL/api/v1/rules/$RULE_REF" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{"enabled": false}' > /dev/null print_status "Rule disabled" # Optionally delete the rule and trigger instance read -p "Delete test rule and trigger instance? (y/N) " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then curl -s -X DELETE "$API_URL/api/v1/rules/$RULE_REF" \ -H "Authorization: Bearer $ACCESS_TOKEN" > /dev/null curl -s -X DELETE "$API_URL/api/v1/trigger-instances/$TRIGGER_INSTANCE_REF" \ -H "Authorization: Bearer $ACCESS_TOKEN" > /dev/null print_status "Test resources deleted" else print_info "Test resources left in place (disabled)" fi echo "" # Final summary echo -e "${BLUE}=== Test Summary ===${NC}" echo "" echo "✓ Runtime detection working (Shell runtime detected)" echo "✓ Core pack loaded with echo action" echo "✓ Trigger instance created (1-second interval timer)" echo "✓ Rule created and enabled" echo "✓ Executions observed: $EXECUTION_COUNT" echo "✓ Successful executions: $SUCCESS_COUNT" echo "" if [ "$SUCCESS_COUNT" -gt 0 ]; then echo -e "${GREEN}=== HAPPY PATH TEST PASSED ===${NC}" echo "" echo "The complete event flow is working:" echo " Timer Sensor → Event → Rule → Enforcement → Execution → Worker → Shell Action" echo "" exit 0 else echo -e "${RED}=== HAPPY PATH TEST FAILED ===${NC}" echo "" echo "Executions were created but none succeeded." echo "Check service logs for errors:" echo " docker logs attune-sensor" echo " docker logs attune-executor" echo " docker logs attune-worker" echo "" exit 1 fi