Files
wehub-resource-sync 4b6817381b
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
CI / coverage-report (push) Has been cancelled
CI / test-kubernetes (push) Has been cancelled
CI / should-run-thorough (push) Has been cancelled
CI / test-thorough (cloudwatch-demo) (push) Has been cancelled
CI / test-thorough (flink-ecs) (push) Has been cancelled
CI / test-thorough (upstream-lambda) (push) Has been cancelled
CI / test-thorough (prefect-ecs-fargate) (push) Has been cancelled
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Has been cancelled
Benchmark image — build + push to ECR (any adapter) / build + push (push) Has been cancelled
CI / quality (ubuntu-latest) (push) Has been cancelled
CI / test (tools-runtime) (push) Has been cancelled
CI / test (e2e-general) (push) Has been cancelled
CI / test (cli-runtime) (push) Has been cancelled
CI / test (e2e-provider-and-openclaw) (push) Has been cancelled
CI / test (integrations-and-misc) (push) Has been cancelled
Release / verify (push) Has been cancelled
Release / build-python-dist (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Has been cancelled
Release / publish-release (push) Has been cancelled
Release / publish-main-release (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Has been cancelled
Release / prepare (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Has been cancelled
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:10:45 +08:00

239 lines
8.2 KiB
Python

"""Infrastructure validation tests for upstream/downstream pipeline.
Tests that the AWS infrastructure and mock pipeline are working correctly.
"""
import json
import sys
import time
from datetime import datetime
import boto3
import requests
def get_stack_outputs(stack_name: str = "TracerUpstreamDownstreamTest") -> dict:
"""Get CloudFormation stack outputs."""
cf_client = boto3.client("cloudformation")
try:
stack = cf_client.describe_stacks(StackName=stack_name)
outputs = {o["OutputKey"]: o["OutputValue"] for o in stack["Stacks"][0]["Outputs"]}
return outputs
except Exception as e:
print(f"ERROR: Could not get stack outputs: {e}")
print(f"Make sure stack '{stack_name}' is deployed")
sys.exit(1)
def test_happy_path(stack_outputs: dict) -> bool:
"""Test 1: Happy path with valid schema."""
print("=" * 60)
print("TEST 1: Happy Path")
print("=" * 60)
# Reset API to good schema
try:
requests.post(
f"{stack_outputs['MockApiUrl']}/config",
json={"inject_schema_change": False},
timeout=10,
)
print("✓ Configured Mock API (good schema)")
except Exception as e:
print(f"✗ Failed to configure Mock API: {e}")
return False
# Verify API returns good data
api_data = requests.get(f"{stack_outputs['MockApiUrl']}/data", timeout=10).json()
has_customer_id = "customer_id" in api_data.get("data", [{}])[0]
print(f"✓ Mock API returns data with customer_id: {has_customer_id}")
if not has_customer_id:
print("✗ TEST FAILED: Mock API should have customer_id")
return False
# Invoke ingester
correlation_id = f"happy-{datetime.utcnow().strftime('%Y%m%d-%H%M%S')}"
lambda_client = boto3.client("lambda")
print(f"Invoking Ingester Lambda (correlation_id={correlation_id})...")
response = lambda_client.invoke(
FunctionName=stack_outputs["IngesterFunctionName"],
Payload=json.dumps({"correlation_id": correlation_id}),
)
result = json.loads(response["Payload"].read())
if result.get("statusCode") != 200:
print(f"✗ Ingester failed: {result}")
return False
s3_key = result["s3_key"]
print(f"✓ Data written to landing: {s3_key}")
# Verify landing bucket has data
s3_client = boto3.client("s3")
try:
obj = s3_client.get_object(Bucket=stack_outputs["LandingBucketName"], Key=s3_key)
landing_data = json.loads(obj["Body"].read())
has_customer_id = "customer_id" in landing_data.get("data", [{}])[0]
print(f"✓ Landing data has customer_id: {has_customer_id}")
if not has_customer_id:
print("✗ TEST FAILED: Landing data should have customer_id")
return False
except Exception as e:
print(f"✗ Failed to read landing data: {e}")
return False
# Wait for Mock DAG processing (S3 event trigger)
print("Waiting 15s for Mock DAG to process...")
time.sleep(15)
# Verify processed output exists
processed_key = s3_key.replace("ingested/", "processed/")
try:
obj = s3_client.get_object(Bucket=stack_outputs["ProcessedBucketName"], Key=processed_key)
processed_data = json.loads(obj["Body"].read())
# Verify transformation occurred
has_amount_cents = "amount_cents" in processed_data.get("data", [{}])[0]
print(f"✓ Processed output exists: {processed_key}")
print(f"✓ Transformation added amount_cents: {has_amount_cents}")
if not has_amount_cents:
print("✗ TEST FAILED: Transform should add amount_cents")
return False
print("✓ HAPPY PATH PASSED")
return True
except s3_client.exceptions.NoSuchKey:
print(f"✗ HAPPY PATH FAILED: No processed output at {processed_key}")
return False
except Exception as e:
print(f"✗ HAPPY PATH FAILED: {e}")
return False
def test_failure_path(stack_outputs: dict) -> bool:
"""Test 2: Failure path with schema mismatch."""
print("\n" + "=" * 60)
print("TEST 2: Failure Path")
print("=" * 60)
# Inject schema change
try:
requests.post(
f"{stack_outputs['MockApiUrl']}/config",
json={"inject_schema_change": True},
timeout=10,
)
print("✓ Configured Mock API (schema change injected)")
except Exception as e:
print(f"✗ Failed to configure Mock API: {e}")
return False
# Verify API returns bad data
api_data = requests.get(f"{stack_outputs['MockApiUrl']}/data", timeout=10).json()
has_customer_id = "customer_id" in api_data.get("data", [{}])[0]
print(f"✓ Mock API returns data WITHOUT customer_id: {not has_customer_id}")
if has_customer_id:
print("✗ TEST FAILED: Mock API should NOT have customer_id")
return False
# Invoke ingester
correlation_id = f"fail-{datetime.utcnow().strftime('%Y%m%d-%H%M%S')}"
lambda_client = boto3.client("lambda")
print(f"Invoking Ingester Lambda (correlation_id={correlation_id})...")
response = lambda_client.invoke(
FunctionName=stack_outputs["IngesterFunctionName"],
Payload=json.dumps({"correlation_id": correlation_id}),
)
result = json.loads(response["Payload"].read())
s3_key = result["s3_key"]
print(f"✓ Bad data written to landing: {s3_key}")
# Verify landing bucket has bad data
s3_client = boto3.client("s3")
try:
obj = s3_client.get_object(Bucket=stack_outputs["LandingBucketName"], Key=s3_key)
landing_data = json.loads(obj["Body"].read())
has_customer_id = "customer_id" in landing_data.get("data", [{}])[0]
print(f"✓ Landing data missing customer_id: {not has_customer_id}")
if has_customer_id:
print("✗ TEST FAILED: Landing data should NOT have customer_id")
return False
except Exception as e:
print(f"✗ Failed to read landing data: {e}")
return False
# Wait for Mock DAG processing
print("Waiting 15s for Mock DAG to process and fail...")
time.sleep(15)
# Verify NO processed output (pipeline should have failed)
processed_key = s3_key.replace("ingested/", "processed/")
try:
s3_client.head_object(Bucket=stack_outputs["ProcessedBucketName"], Key=processed_key)
print(f"✗ FAILURE PATH FAILED: Output exists at {processed_key} (should have failed)")
return False
except Exception as e:
# Should fail (object doesn't exist)
if "404" in str(e) or "NoSuchKey" in str(e):
print("✓ No processed output (correctly failed)")
else:
print(f"✗ Unexpected error checking processed output: {e}")
return False
# Verify error in CloudWatch logs
logs_client = boto3.client("logs")
log_group = f"/aws/lambda/{stack_outputs['MockDagFunctionName']}"
try:
response = logs_client.filter_log_events(
logGroupName=log_group,
startTime=int((time.time() - 300) * 1000),
filterPattern="Schema validation failed",
)
if response["events"]:
error_msg = response["events"][0]["message"]
print("✓ Error logged in CloudWatch:")
print(f" {error_msg[:200]}")
print("✓ FAILURE PATH PASSED")
return True
else:
print("✗ FAILURE PATH FAILED: No error in logs")
print(f" Check log group: {log_group}")
return False
except Exception as e:
print(f"✗ Failed to check CloudWatch logs: {e}")
return False
if __name__ == "__main__":
# Get stack outputs
print("Getting stack outputs...")
stack_outputs = get_stack_outputs()
# Run tests
happy_passed = test_happy_path(stack_outputs)
failure_passed = test_failure_path(stack_outputs)
# Summary
print("\n" + "=" * 60)
print("TEST SUMMARY")
print("=" * 60)
print(f" Happy Path: {'PASSED' if happy_passed else 'FAILED'}")
print(f" Failure Path: {'PASSED' if failure_passed else 'FAILED'}")
print()
if all([happy_passed, failure_passed]):
print("✓ ALL TESTS PASSED")
sys.exit(0)
else:
print("✗ SOME TESTS FAILED")
sys.exit(1)