Skip to content

Week 4: User Acceptance Testing (UAT) and Sign-Off

Test Matrix Week 4

┌────┬─────────────────────────────────────────────────────────┬────────┐
│ ID │ UAT Scenario                                            │ Pass   │
├────┼─────────────────────────────────────────────────────────┼────────┤
│4.1 │ Simulated workday: Teams + O365 + Salesforce user flow │ No err │
│4.2 │ Developer: GCP Vertex AI model inference               │ <2s    │
│4.3 │ Finance: Azure SQL query from branch                   │ <500ms │
│4.4 │ IOT device: MQTT publish to cloud                      │ <100ms │
│4.5 │ Security: Umbrella blocks malicious domain             │ Blocked│
│4.6 │ SIEM: Splunk alert triggered on simulated threat       │ <5min  │
│4.7 │ AppDynamics: Full trace branch→hub→Azure transaction   │ Traced │
│4.8 │ ThousandEyes: Path change correlates with Splunk alert │ Correl │
│4.9 │ Performance baseline documentation                     │ Signed │
│4.10│ NOC: Runbook execution drill                           │ Passed │
└────┴─────────────────────────────────────────────────────────┴────────┘

TEST 4.1: Simulated Workday (End-User Experience)

#!/usr/bin/env python3

"""
Simulated workday user experience test
Runs sequentially as a typical Abhavtech employee would work
"""

import requests
import time
import subprocess
import json

def measure_latency(url, count=5, timeout=5):
    """Measure HTTP response time"""
    times = []
    for _ in range(count):
        try:
            start = time.time()
            r = requests.get(url, timeout=timeout, verify=False)
            elapsed = (time.time() - start) * 1000
            times.append((r.status_code, elapsed))
        except requests.Timeout:
            times.append((0, timeout * 1000))
        time.sleep(0.5)
    return times

def run_workday_simulation():
    print("=" * 65)
    print("  SIMULATED WORKDAY — END-USER EXPERIENCE TEST")
    print(f"  Started: {time.strftime('%Y-%m-%d %H:%M:%S')}")
    print("=" * 65)

    tests = [
        {
            "name": "Outlook Web Access (Exchange Online)",
            "url": "https://outlook.office365.com",
            "threshold_ms": 500,
            "expected_status": 200
        },
        {
            "name": "Teams Web Client",
            "url": "https://teams.microsoft.com",
            "threshold_ms": 500,
            "expected_status": 200
        },
        {
            "name": "SharePoint (Document Access)",
            "url": "https://abhavtech.sharepoint.com",
            "threshold_ms": 800,
            "expected_status": 200
        },
        {
            "name": "Salesforce CRM",
            "url": "https://abhavtech.my.salesforce.com",
            "threshold_ms": 1000,
            "expected_status": 200
        },
        {
            "name": "ServiceNow ITSM",
            "url": "https://abhavtech.service-now.com",
            "threshold_ms": 1000,
            "expected_status": 200
        },
        {
            "name": "Workday HCM",
            "url": "https://wd3.myworkday.com/abhavtech/login.htmld",
            "threshold_ms": 1500,
            "expected_status": 200
        },
        {
            "name": "Azure SQL via Private Endpoint (ODBC)",
            "url": None,
            "host": "10.100.10.10",
            "port": 1433,
            "threshold_ms": 500
        },
        {
            "name": "GCP Vertex AI API",
            "url": "https://asia-south1-aiplatform.googleapis.com",
            "threshold_ms": 50,
            "expected_status": 401   # Unauthorized without token — still proves reachability
        }
    ]

    results = []
    for test in tests:
        print(f"\n--- {test['name']} ---")

        if test.get("url"):
            measurements = measure_latency(test["url"])
            avg_ms = sum(m[1] for m in measurements) / len(measurements)
            status_codes = [m[0] for m in measurements]

            ok = avg_ms < test["threshold_ms"] and any(
                s in [test.get("expected_status", 200), 200, 201, 302]
                for s in status_codes
            )
            icon = "✅" if ok else "❌"
            print(f"  {icon} Avg latency: {avg_ms:.0f}ms | Threshold: {test['threshold_ms']}ms | "
                  f"Status: {status_codes[0]}")
        else:
# TCP port test (Azure SQL)

            import socket
            start = time.time()
            try:
                s = socket.create_connection((test["host"], test["port"]), timeout=5)
                elapsed = (time.time() - start) * 1000
                s.close()
                ok = elapsed < test["threshold_ms"]
                icon = "✅" if ok else "⚠️"
                print(f"  {icon} TCP connect: {elapsed:.0f}ms | Threshold: {test['threshold_ms']}ms")
            except Exception as e:
                print(f"  ❌ Connection failed: {e}")
                ok = False

        results.append({"test": test["name"], "passed": ok})

## Summary

    passed = sum(1 for r in results if r["passed"])
    total = len(results)
    print(f"\n{'=' * 65}")
    print(f"  UAT 4.1 RESULT: {passed}/{total} applications meeting SLA")
    print(f"  {'✅ PASS — Ready for production sign-off' if passed == total else '❌ FAIL — Resolve failures before sign-off'}")
    print("=" * 65)


if __name__ == "__main__":
    run_workday_simulation()

TEST 4.5: Umbrella Security (Malicious Domain Block)

#!/bin/bash

## umbrella_security_test.sh


echo "=== TEST 4.5: UMBRELLA SECURITY CONTROLS ==="

## Test from Bangalore branch — these should all be BLOCKED by Umbrella DNS

MALICIOUS_DOMAINS=(
  "malwaredomainlist.com"         # Known malware C2
  "phishtank.org"                 # Phishing test domain
  "www.eicar.org"                 # EICAR malware test
)

BRANCH="blr-br-01"
UMBRELLA_BLOCK_IP="146.112.62.40"    # Umbrella block page IP

echo ""
echo "Testing from Bangalore branch (DNS via Umbrella 208.67.222.222):"

for DOMAIN in "${MALICIOUS_DOMAINS[@]}"; do
  RESULT=$(ssh admin@$BRANCH "nslookup $DOMAIN 208.67.222.222 2>/dev/null | grep 'Address' | tail -1 | awk '{print \$2}'" 2>/dev/null)
  if [[ "$RESULT" == "146.112.62.40" ]] || [[ "$RESULT" == "146.112.63."* ]] || [[ "$RESULT" == "NXDOMAIN" ]]; then
    echo "  ✅ BLOCKED: $DOMAIN$RESULT (Umbrella block page)"
  else
    echo "  ❌ NOT BLOCKED: $DOMAIN$RESULT"
  fi
done

## Test DNSCrypt is active (DNS queries encrypted)

echo ""
echo "--- DNSCrypt Encryption ---"
ssh admin@$BRANCH "show umbrella dnscrypt" 2>/dev/null | grep -i "enabled\|disabled"
## Expected: DNSCrypt: Enabled


## Test SWG is blocking a banned category (gambling)

echo ""
echo "--- SWG URL Category Block (Gambling) ---"
GAMBLING_TEST=$(ssh admin@$BRANCH "curl -s -o /dev/null -w '%{http_code}' --max-time 5 https://www.bet365.com" 2>/dev/null)
[[ "$GAMBLING_TEST" == "403" ]] || [[ "$GAMBLING_TEST" == "000" ]] && \
  echo "  ✅ Gambling site blocked by SWG (HTTP $GAMBLING_TEST)" || \
  echo "  ⚠️  Gambling site returned HTTP $GAMBLING_TEST (check SWG policy)"

TEST 4.6: Splunk SIEM Alert Triggered

#!/bin/bash

## splunk_alert_test.sh


echo "=== TEST 4.6: SPLUNK SIEM ALERT PIPELINE ==="

## Generate a simulated security event: repeated auth failure

## This should trigger Splunk MLTK alert → ServiceNow ticket

echo "--- Generating test event: 5 failed SSH logins to 10.100.1.50 ---"

for i in $(seq 1 5); do
  ssh -o StrictHostKeyChecking=no -o ConnectTimeout=2 \
    baduser@10.100.1.50 "test" 2>/dev/null || true
  sleep 1
done

echo "Events generated. Waiting 5 minutes for Splunk to alert..."
sleep 300

## Check if Splunk alert fired

SPLUNK_HOST="splunk.abhavtech.com"
ALERT_CHECK=$(curl -s -k -u "admin:<PASSWORD>" \
  "https://$SPLUNK_HOST:8089/services/alerts/fired_alerts" \
  -G --data "output_mode=json" | \
  python3 -c "
import json, sys
data = json.load(sys.stdin)
alerts = data.get('entry', [])
recent = [a for a in alerts if 'auth' in a.get('name','').lower() or 'fail' in a.get('name','').lower()]
print(f'Recent auth-related alerts: {len(recent)}')
for a in recent[:3]:
    print(f'  {a[\"name\"]} — {a.get(\"content\",{}).get(\"triggered_at\",\"?\")}')
" 2>/dev/null)

echo "$ALERT_CHECK"
echo ""
echo "Pass Criteria: Auth failure alert triggered within 5 minutes"

TEST 4.8: ThousandEyes + Splunk Correlation

#!/bin/bash

## thousandeyes_splunk_correlation.sh


echo "=== TEST 4.8: THOUSANDEYES ↔ SPLUNK CORRELATION ==="

TE_TOKEN="<TE_BEARER_TOKEN>"

## Step 1: Get a known ThousandEyes alert (recent)

TE_ALERTS=$(curl -s -X GET "https://api.thousandeyes.com/v7/alerts?state=active" \
  -H "Authorization: Bearer $TE_TOKEN" | \
  python3 -c "
import json,sys
data = json.load(sys.stdin)
alerts = data.get('alerts', [])
if alerts:
    a = alerts[0]
    print(f'Alert ID: {a.get(\"alertId\")}')
    print(f'Test:     {a.get(\"testName\")}')
    print(f'Time:     {a.get(\"startDate\")}')
    print(f'Type:     {a.get(\"type\")}')
else:
    print('No active TE alerts — simulating one...')
")

echo "$TE_ALERTS"

## Step 2: Verify same event is in Splunk

echo ""
echo "--- Checking Splunk for correlated ThousandEyes event ---"
curl -s -k -u "admin:<PASSWORD>" \
  "https://splunk.abhavtech.com:8089/services/search/jobs/oneshot" \
  --data-urlencode "search=index=thousandeyes sourcetype=thousandeyes:alert earliest=-30m | head 3" \
  -d "output_mode=json" | \
  python3 -c "
import json,sys
data = json.load(sys.stdin)
results = data.get('results', [])
print(f'TE alerts in Splunk (last 30 min): {len(results)}')
for r in results[:3]:
    print(f'  {r}')
"

echo ""
echo "Pass Criteria: ThousandEyes alert appears in Splunk within 5 minutes (polling interval)"