#!/bin/bash # ============================================================================== # WellDrySense API Test Suite (Bash Version) # Functionality: Exercises Job APIs including Create, List, Edit, Details, Weather, # Sensor Data, and performs Database Cleanup. # ============================================================================== # --- Configuration --- # Load .env file if it exists if [ -f .env ]; then export $(cat .env | xargs) fi # Defaults (can be overridden by env vars) PORT="${PORT:-8002}" BASE_URL="http://localhost:$PORT/api/well_api" API_USER="${API_USER:-jpeters}" API_PASSWORD="${API_PASSWORD:-WellJson}" DB_NAME="${DB_NAME:-wellnuo}" DB_USER="${DB_USER:-postgres}" DB_HOST="${DB_HOST:-localhost}" DB_PORT="${DB_PORT:-5432}" # DB_PASSWORD should be set in .env or exported # Colors GREEN='\033[0;32m' RED='\033[0;31m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Global Variables TOKEN="" USER_ID="" JOB_ID="" # Check for jq if ! command -v jq &> /dev/null; then echo -e "${RED}Error: 'jq' is not installed. Please install it to run this script.${NC}" exit 1 fi echo -e "${BLUE}=== Setting up WellDrySense Test Suite on Port $PORT ===${NC}" # ============================================================================== # Helper Functions # ============================================================================== # Function to print section headers print_header() { echo -e "\n${BLUE}----------------------------------------------------------------${NC}" echo -e "${BLUE}[Test] $1${NC}" } # Function to perform a POST request # Usage: perform_test "Test Name" "JSON_PAYLOAD_STRING" perform_test() { local test_name="$1" local json_payload="$2" print_header "$test_name" # 1. Print Request echo "# Request:" echo "$json_payload" | jq '.' # 2. Convert JSON to Form Data for curl (flattening simple objects) # Note: This simple conversion handles top-level keys. # Complex nested JSON strings (like 'devices') need to be passed as strings in the input JSON. local form_data="" # Extract keys and values and build form string while IFS="=" read -r key value; do if [ -n "$key" ]; then # URL encode the value encoded_value=$(printf '%s' "$value" | jq -sRr @uri) if [ -z "$form_data" ]; then form_data="${key}=${encoded_value}" else form_data="${form_data}&${key}=${encoded_value}" fi fi done < <(echo "$json_payload" | jq -r "to_entries|map(\"\(.key)=\(.value)\")|.[]") # 3. Execute Request response=$(curl -s -X POST "$BASE_URL" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "$form_data") # 4. Print Response echo -e "\n# Response:" if [ -z "$response" ]; then echo "(Empty Response)" echo -e "${RED}FAIL${NC}" return 1 else echo "$response" | jq '.' 2>/dev/null || echo "$response" fi # 5. Evaluate Pass/Fail based on "ok": 1 ok_val=$(echo "$response" | jq -r '.ok // .status // 0') # Handle different response structures (some return {status: 200}, some {ok: 1}) if [ "$ok_val" == "1" ] || [ "$ok_val" == "200" ] || [ "$ok_val" == "success" ]; then echo -e "${GREEN}PASS${NC}" # Extract Job ID if this was the create step if [ "$test_name" == "job_create" ]; then JOB_ID=$(echo "$response" | jq -r '.job_id') echo "-> Captured Job ID: $JOB_ID" fi return 0 else error_msg=$(echo "$response" | jq -r '.error // .message // "Unknown error"') echo -e "${RED}FAIL: $error_msg${NC}" return 1 fi } # ============================================================================== # Test Execution # ============================================================================== # 1. Login / Credentials # ---------------------- login_payload=$(jq -n \ --arg fn "credentials" \ --arg un "$API_USER" \ --arg ps "$API_PASSWORD" \ --arg cid "bash-suite" \ --arg nonce "test-nonce" \ '{function: $fn, user_name: $un, ps: $ps, clientId: $cid, nonce: $nonce}') print_header "Login" echo "# Request:" echo "$login_payload" | jq '.' # Special handling for login to capture token response=$(curl -s -X POST "$BASE_URL" -d "function=credentials&user_name=$API_USER&ps=$API_PASSWORD&clientId=bash-suite&nonce=test-nonce") echo -e "\n# Response:" echo "$response" | jq '.' TOKEN=$(echo "$response" | jq -r '.access_token // .data.access_token') USER_ID=$(echo "$response" | jq -r '.user_id // .data.user_id') if [ -n "$TOKEN" ] && [ "$TOKEN" != "null" ]; then echo -e "${GREEN}PASS${NC} (User ID: $USER_ID)" else echo -e "${RED}FATAL: Login failed. Check credentials.${NC}" exit 1 fi # 2. Create Job # ---------------------- # Note: We pass JSON strings for complex fields like 'devices' and 'alerts_config' devices_json='[{"mac": "TEST_MAC_VIRTUAL", "location": "Lab"}]' alerts_json='{"temp_high": 30}' create_payload=$(jq -n \ --arg fn "job_create" \ --arg un "$API_USER" \ --arg tk "$TOKEN" \ --arg cn "TEST_SUITE_CUSTOMER_BASH" \ --arg as "123 Bash Script Ln" \ --arg ac "Shellville" \ --arg dev "$devices_json" \ --arg lat "34.05" \ --arg lng "-118.25" \ '{function: $fn, user_name: $un, token: $tk, customer_name: $cn, address_street: $as, address_city: $ac, devices: $dev, lat: $lat, lng: $lng}') perform_test "job_create" "$create_payload" || exit 1 # 3. Job List # ---------------------- list_payload=$(jq -n \ --arg fn "job_list" \ --arg un "$API_USER" \ --arg tk "$TOKEN" \ '{function: $fn, user_name: $un, token: $tk}') perform_test "job_list" "$list_payload" # 3. Job List 2 (with added search) # ---------------------- list_payload=$(jq -n \ --arg fn "job_list2" \ --arg un "$API_USER" \ --arg tk "$TOKEN" \ --arg sch "" \ '{function: $fn, user_name: $un, token: $tk, search: $sch}') perform_test "job_list2" "$list_payload" # 4. Job Details # ---------------------- details_payload=$(jq -n \ --arg fn "job_details" \ --arg un "$API_USER" \ --arg tk "$TOKEN" \ --arg jid "$JOB_ID" \ '{function: $fn, user_name: $un, token: $tk, job_id: $jid}') perform_test "job_details" "$details_payload" # 5. Job Edit (Stop Job) # ---------------------- edit_payload=$(jq -n \ --arg fn "job_edit" \ --arg un "$API_USER" \ --arg tk "$TOKEN" \ --arg jid "$JOB_ID" \ --arg st "Stopped" \ --arg dt "2025-12-31T23:59:59" \ '{function: $fn, user_name: $un, token: $tk, job_id: $jid, job_status: $st, date_to: $dt}') perform_test "job_edit" "$edit_payload" # 6. Available Devices (two versions, with direct SQL and via GetProximityList) # ---------------------- avail_payload=$(jq -n \ --arg fn "job_available_devices" \ --arg un "$API_USER" \ --arg tk "$TOKEN" \ '{function: $fn, user_name: $un, token: $tk}') perform_test "job_available_devices" "$avail_payload" # 6. Available Devices (Alternative Test using job_available_devices2, which is using GetProximityList) avail_payload=$(jq -n \ --arg fn "job_available_devices2" \ --arg un "$API_USER" \ --arg tk "$TOKEN" \ '{function: $fn, user_name: $un, token: $tk}') perform_test "job_available_devices2" "$avail_payload" # 6. Available Devices(made reusing job_user_all_devices2, adding filter and search) avail_payload=$(jq -n \ --arg fn "job_devices" \ --arg un "$API_USER" \ --arg tk "$TOKEN" \ --arg fl "all" \ --arg sch "" \ '{function: $fn, user_name: $un, token: $tk, filter: $fl, search: $sch}') perform_test "job_devices" "$avail_payload" # 7. Job Weather # ---------------------- weather_payload=$(jq -n \ --arg fn "job_weather" \ --arg un "$API_USER" \ --arg tk "$TOKEN" \ --arg jid "$JOB_ID" \ '{function: $fn, user_name: $un, token: $tk, job_id: $jid}') perform_test "job_weather" "$weather_payload" # 8. Job Sensor Bucketed Data (New Test) # ---------------------- # Using dynamic dates for the test DATE_FROM=$(date +%Y-%m-%d) DATE_TO=$(date +%Y-%m-%d) sensor_payload=$(jq -n \ --arg fn "get_job_sensor_bucketed_data" \ --arg un "$API_USER" \ --arg tk "$TOKEN" \ --arg jid "$JOB_ID" \ --arg sens "temperature" \ --arg dt "$DATE_FROM" \ --arg dtt "$DATE_TO" \ --arg bs "15m" \ '{function: $fn, user_name: $un, token: $tk, job_id: $jid, sensor: $sens, date: $dt, to_date: $dtt, bucket_size: $bs}') perform_test "get_job_sensor_bucketed_data" "$sensor_payload" # ============================================================================== # Cleanup # ============================================================================== print_header "Cleanup" if [ -n "$JOB_ID" ]; then echo "-> Deleting Job ID: $JOB_ID from database..." # Use PGPASSWORD for non-interactive auth if set export PGPASSWORD="${DB_PASSWORD}" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -c "DELETE FROM public.jobs WHERE job_id = $JOB_ID;" > /dev/null 2>&1 if [ $? -eq 0 ]; then echo -e "${GREEN}Cleanup successful. Database restored.${NC}" else echo -e "${RED}Cleanup failed. Please manually delete job_id $JOB_ID from public.jobs.${NC}" echo "Command attempted: psql -h $DB_HOST -U $DB_USER -d $DB_NAME -c \"DELETE FROM public.jobs WHERE job_id = $JOB_ID;\"" fi else echo "No Job ID created, skipping cleanup." fi echo -e "\n${BLUE}=== Test Suite Finished ===${NC}" # ============================================================================== # well-api.py modifications to support WellDrySense API on port 1998 # ==============================================================================