|
1 | 1 | import boto3 |
2 | | -import gzip |
3 | 2 | import json |
4 | | -import os |
5 | 3 | import pytest |
6 | | -import requests |
7 | 4 | import subprocess |
8 | 5 | import time |
9 | | -import threading |
10 | 6 | import yaml |
11 | 7 |
|
12 | | -from aws_cdk import ( |
13 | | - App, |
14 | | - CfnResource, |
15 | | - Stack, |
16 | | -) |
17 | | -from constructs import Construct |
18 | | -from fastapi import FastAPI, Request |
19 | | -import uvicorn |
| 8 | +from aws_cdk import App |
20 | 9 |
|
21 | | -from scripts.build_aws_lambda_layer import build_packaged_zip, DIST_PATH |
| 10 | +from .utils import DummyLambdaStack, SentryTestServer, SAM_PORT, SAM_REGION |
22 | 11 |
|
23 | | - |
24 | | -SAM_PORT = 3001 |
25 | | -SAM_REGION = "us-east-1" |
26 | 12 | SAM_TEMPLATE_FILE = "sam.template.yaml" |
27 | 13 |
|
28 | 14 |
|
29 | | -class DummyLambdaStack(Stack): |
30 | | - def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: |
31 | | - super().__init__(scope, construct_id, **kwargs) |
32 | | - |
33 | | - # Override the template synthesis |
34 | | - self.template_options.template_format_version = "2010-09-09" |
35 | | - self.template_options.transforms = ["AWS::Serverless-2016-10-31"] |
36 | | - |
37 | | - # Create Sentry Lambda Layer |
38 | | - filename = "sentry-sdk-lambda-layer.zip" |
39 | | - build_packaged_zip( |
40 | | - make_dist=True, |
41 | | - out_zip_filename=filename, |
42 | | - ) |
43 | | - |
44 | | - layer = CfnResource( |
45 | | - self, |
46 | | - "SentryPythonServerlessSDK", |
47 | | - type="AWS::Serverless::LayerVersion", |
48 | | - properties={ |
49 | | - "ContentUri": os.path.join(DIST_PATH, filename), |
50 | | - "CompatibleRuntimes": [ |
51 | | - "python3.7", |
52 | | - "python3.8", |
53 | | - "python3.9", |
54 | | - "python3.10", |
55 | | - "python3.11", |
56 | | - "python3.12", |
57 | | - "python3.13", |
58 | | - ], |
59 | | - }, |
60 | | - ) |
61 | | - |
62 | | - # Add the function using SAM format |
63 | | - CfnResource( |
64 | | - self, |
65 | | - "BasicTestFunction", |
66 | | - type="AWS::Serverless::Function", |
67 | | - properties={ |
68 | | - "CodeUri": "./tests/integrations/aws_lambda/lambda_functions/hello_world", |
69 | | - "Handler": "sentry_sdk.integrations.init_serverless_sdk.sentry_lambda_handler", |
70 | | - "Runtime": "python3.12", |
71 | | - "Layers": [{"Ref": layer.logical_id}], # The layer adds the sentry-sdk |
72 | | - "Environment": { # The environment variables are set up the Sentry SDK to instrument the lambda function |
73 | | - "Variables": { |
74 | | - "SENTRY_DSN": "http://[email protected]:9999/0", |
75 | | - "SENTRY_INITIAL_HANDLER": "index.handler", |
76 | | - "SENTRY_TRACES_SAMPLE_RATE": "1.0", |
77 | | - } |
78 | | - }, |
79 | | - }, |
80 | | - ) |
81 | | - |
82 | | - @classmethod |
83 | | - def wait_for_stack(cls, timeout=30, port=SAM_PORT): |
84 | | - """ |
85 | | - Wait for SAM to be ready, with timeout. |
86 | | - """ |
87 | | - start_time = time.time() |
88 | | - while True: |
89 | | - if time.time() - start_time > timeout: |
90 | | - raise TimeoutError( |
91 | | - "SAM failed to start within {} seconds".format(timeout) |
92 | | - ) |
93 | | - |
94 | | - try: |
95 | | - # Try to connect to SAM |
96 | | - response = requests.get(f"http://127.0.0.1:{port}/") |
97 | | - if response.status_code == 200 or response.status_code == 404: |
98 | | - return |
99 | | - |
100 | | - except requests.exceptions.ConnectionError: |
101 | | - time.sleep(1) |
102 | | - continue |
103 | | - |
104 | | - |
105 | | -class SentryTestServer: |
106 | | - def __init__(self, port=9999): |
107 | | - self.envelopes = [] |
108 | | - self.port = port |
109 | | - self.app = FastAPI() |
110 | | - |
111 | | - @self.app.post("/api/0/envelope/") |
112 | | - async def envelope(request: Request): |
113 | | - print("[SENTRY SERVER] Received envelope") |
114 | | - try: |
115 | | - raw_body = await request.body() |
116 | | - except: |
117 | | - return {"status": "no body"} |
118 | | - |
119 | | - try: |
120 | | - body = gzip.decompress(raw_body).decode("utf-8") |
121 | | - except: |
122 | | - # If decompression fails, assume it's plain text |
123 | | - body = raw_body.decode("utf-8") |
124 | | - |
125 | | - lines = body.split("\n") |
126 | | - |
127 | | - current_line = 1 # line 0 is envelope header |
128 | | - while current_line < len(lines): |
129 | | - # skip empty lines |
130 | | - if not lines[current_line].strip(): |
131 | | - current_line += 1 |
132 | | - continue |
133 | | - |
134 | | - # skip envelope item header |
135 | | - current_line += 1 |
136 | | - |
137 | | - # add envelope item to store |
138 | | - envelope_item = lines[current_line] |
139 | | - if envelope_item.strip(): |
140 | | - self.envelopes.append(json.loads(envelope_item)) |
141 | | - |
142 | | - return {"status": "ok"} |
143 | | - |
144 | | - def run_server(self): |
145 | | - uvicorn.run(self.app, host="0.0.0.0", port=self.port) |
146 | | - |
147 | | - def start(self): |
148 | | - print("[SENTRY SERVER] Starting server") |
149 | | - server_thread = threading.Thread(target=self.run_server, daemon=True) |
150 | | - server_thread.start() |
151 | | - |
152 | | - def clear_envelopes(self): |
153 | | - print("[SENTRY SERVER] Clear envelopes") |
154 | | - self.envelopes = [] |
155 | | - |
156 | | - |
157 | 15 | @pytest.fixture(scope="session", autouse=True) |
158 | 16 | def test_environment(): |
159 | 17 | print("Setting up AWS Lambda test infrastructure") |
@@ -221,7 +79,7 @@ def clear_before_test(test_environment): |
221 | 79 | @pytest.fixture |
222 | 80 | def lambda_client(): |
223 | 81 | """ |
224 | | - Create a boto3 client configured to use SAM local |
| 82 | + Create a boto3 client configured to use the local AWS SAM instance. |
225 | 83 | """ |
226 | 84 | return boto3.client( |
227 | 85 | "lambda", |
@@ -256,7 +114,3 @@ def test_basic_2(lambda_client, test_environment): |
256 | 114 | message, transaction = test_environment["server"].envelopes |
257 | 115 | assert message["message"] == "[SENTRY MESSAGE] Hello, Neel!" |
258 | 116 | assert transaction["type"] == "transaction" |
259 | | - |
260 | | - |
261 | | -# what is not working: |
262 | | -# i should improve how the server are started and stopped at the beginning and end of the test session. |
0 commit comments