Skip to content

Commit bad4bd2

Browse files
committed
add proxy tests for Cognito-IDP
1 parent 7640e44 commit bad4bd2

2 files changed

Lines changed: 160 additions & 3 deletions

File tree

aws-proxy/AGENTS.md

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,30 @@
1-
# AI Agent Instructions for AWS Proxy Extension
1+
# AI Agent Instructions for LocalStack AWS Proxy Extension
22

33
This repo is a LocalStack extension (plugin) that enables a "proxy mode" - proxying requests for certain AWS services (e.g., S3) to the upstream real AWS cloud, while handling the remaining services locally.
44

5+
You are an AI agent tasked with adding additional functionality or test coverage to this repo.
6+
7+
## General Instructions
8+
9+
* You can assume that the LocalStack container is running locally, with the proxy extension installed and enabled.
10+
* You can assume that test AWS credentials are configured in the shell environment where the AI agent is running.
11+
* Do *not* touch any files outside the working directory (basedir of this file)!
12+
* You can create new files (no need to prompt for confirmation)
13+
* You can make modifications to files (no need to prompt for confirmation)
14+
* You can delete existing files if needed, but only after user confirmation
15+
* You can call different `make` targets (e.g., `make test`) in this repo (no need to prompt for confirmation)
16+
* For each new file created or existing file modified, add a header comment to the file, something like `# Note/disclosure: This file has been (partially or fully) generated by an AI agent.`
17+
* The proxy tests are executed against real AWS and may incur some costs, so rather than executing the entire test suite or entire modules, focus the testing on individual test functions within a module only.
18+
519
## Testing
620

7-
The proxy functionality is covered by integration tests in the `tests/` folder, one file for each different service.
21+
The proxy functionality is covered by integration tests in the `tests/` folder, one file for each different AWS service (e.g., SQS, S3, etc).
822

923
To add a test, follow the pattern in the existing tests.
1024
It usually involves creating two boto3 clients, one for the LocalStack connection, and one for the real upstream AWS cloud.
1125
We then run API requests with both clients and assert that the results are identical, thereby ensuring that the proxy functionality is working properly.
1226

13-
You can assume that test AWS credentials are configured in the shell environment where the AI agent is running.
27+
To run a single test via `pytest` (say, `test_my_logic` in `test_s3.py`), use the following command:
28+
```
29+
TEST_PATH=tests/test_s3.py::test_my_logic make test
30+
```
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
# Note/disclosure: This file has been (partially or fully) generated by an AI agent.
2+
3+
import boto3
4+
import pytest
5+
from botocore.exceptions import ClientError
6+
from localstack.aws.connect import connect_to
7+
from localstack.utils.sync import retry
8+
9+
from aws_proxy.shared.models import ProxyConfig
10+
11+
12+
def _compare_user_pool_lists(user_pools_aws: list, user_pools_proxied: list):
13+
# Helper to compare user pool lists, ignoring some dynamic attributes
14+
# We'll need to refine this based on actual Cognito-IDP response structure
15+
def normalize_user_pool(user_pool):
16+
normalized = user_pool.copy()
17+
normalized.pop("LastModifiedDate", None)
18+
normalized.pop("CreationDate", None)
19+
return normalized
20+
21+
normalized_aws = sorted([normalize_user_pool(up) for up in user_pools_aws], key=lambda x: x["Id"])
22+
normalized_proxied = sorted([normalize_user_pool(up) for up in user_pools_proxied], key=lambda x: x["Id"])
23+
24+
assert normalized_proxied == normalized_aws
25+
26+
27+
def test_cognito_idp_user_pool_operations(start_aws_proxy):
28+
# Start proxy for cognito-idp service
29+
config = ProxyConfig(services={"cognito-idp": {"resources": ".*"}})
30+
start_aws_proxy(config)
31+
32+
# Create clients
33+
cognito_client = connect_to().cognito_idp
34+
cognito_client_aws = boto3.client("cognito-idp")
35+
36+
# List user pools initially to ensure clean state and compare
37+
user_pools_proxied_initial = cognito_client.list_user_pools(MaxResults=10)["UserPools"]
38+
user_pools_aws_initial = cognito_client_aws.list_user_pools(MaxResults=10)["UserPools"]
39+
_compare_user_pool_lists(user_pools_aws_initial, user_pools_proxied_initial)
40+
41+
# Create a user pool
42+
user_pool_name = "test-user-pool-proxy"
43+
create_response_proxied = cognito_client.create_user_pool(PoolName=user_pool_name)
44+
user_pool_id_proxied = create_response_proxied["UserPool"]["Id"]
45+
46+
# List user pools and compare
47+
user_pools_proxied_after_create = cognito_client.list_user_pools(MaxResults=10)["UserPools"]
48+
user_pools_aws_after_create = cognito_client_aws.list_user_pools(MaxResults=10)["UserPools"]
49+
_compare_user_pool_lists(user_pools_aws_after_create, user_pools_proxied_after_create)
50+
51+
# Describe user pool and compare
52+
describe_proxied = cognito_client.describe_user_pool(UserPoolId=user_pool_id_proxied)["UserPool"]
53+
describe_aws = cognito_client_aws.describe_user_pool(UserPoolId=user_pool_id_proxied)["UserPool"]
54+
# Normalize for comparison (remove dynamic fields)
55+
describe_proxied.pop("LastModifiedDate", None)
56+
describe_proxied.pop("CreationDate", None)
57+
describe_aws.pop("LastModifiedDate", None)
58+
describe_aws.pop("CreationDate", None)
59+
assert describe_proxied == describe_aws
60+
61+
# Delete the user pool
62+
cognito_client.delete_user_pool(UserPoolId=user_pool_id_proxied)
63+
64+
def _assert_user_pool_deleted():
65+
with pytest.raises(ClientError) as aws_exc:
66+
cognito_client_aws.describe_user_pool(UserPoolId=user_pool_id_proxied)
67+
with pytest.raises(ClientError) as proxied_exc:
68+
cognito_client.describe_user_pool(UserPoolId=user_pool_id_proxied)
69+
assert aws_exc.value.response["Error"]["Code"] == "ResourceNotFoundException"
70+
assert proxied_exc.value.response["Error"]["Code"] == "ResourceNotFoundException"
71+
72+
retry(_assert_user_pool_deleted, retries=5, sleep=5)
73+
74+
# Verify that the user pool is no longer in the list
75+
user_pools_proxied_final = cognito_client.list_user_pools(MaxResults=10)["UserPools"]
76+
user_pools_aws_final = cognito_client_aws.list_user_pools(MaxResults=10)["UserPools"]
77+
_compare_user_pool_lists(user_pools_aws_final, user_pools_proxied_final)
78+
79+
80+
def test_cognito_idp_user_operations(start_aws_proxy):
81+
# Start proxy for cognito-idp service
82+
config = ProxyConfig(services={"cognito-idp": {"resources": ".*"}})
83+
start_aws_proxy(config)
84+
85+
# Create clients
86+
cognito_client = connect_to().cognito_idp
87+
cognito_client_aws = boto3.client("cognito-idp")
88+
89+
# Create a user pool
90+
user_pool_name = "test-user-pool-users-proxy"
91+
user_pool = cognito_client.create_user_pool(PoolName=user_pool_name)
92+
user_pool_id = user_pool["UserPool"]["Id"]
93+
94+
try:
95+
# Create a user pool client
96+
user_pool_client = cognito_client.create_user_pool_client(
97+
UserPoolId=user_pool_id,
98+
ClientName="test-client",
99+
ExplicitAuthFlows=["ADMIN_NO_SRP_AUTH", "USER_PASSWORD_AUTH"],
100+
)
101+
client_id = user_pool_client["UserPoolClient"]["ClientId"]
102+
103+
# Sign up a user
104+
username = "testuser"
105+
password = "Password123!"
106+
cognito_client.sign_up(
107+
ClientId=client_id,
108+
Username=username,
109+
Password=password,
110+
UserAttributes=[{"Name": "email", "Value": "test@example.com"}],
111+
)
112+
113+
# Confirm the user
114+
cognito_client.admin_confirm_sign_up(UserPoolId=user_pool_id, Username=username)
115+
116+
# Initiate auth
117+
auth_response_proxied = cognito_client.initiate_auth(
118+
ClientId=client_id,
119+
AuthFlow="USER_PASSWORD_AUTH",
120+
AuthParameters={"USERNAME": username, "PASSWORD": password},
121+
)
122+
auth_response_aws = cognito_client_aws.initiate_auth(
123+
ClientId=client_id,
124+
AuthFlow="USER_PASSWORD_AUTH",
125+
AuthParameters={"USERNAME": username, "PASSWORD": password},
126+
)
127+
assert auth_response_proxied["AuthenticationResult"]["AccessToken"]
128+
assert auth_response_aws["AuthenticationResult"]["AccessToken"]
129+
130+
# Admin delete user
131+
cognito_client.admin_delete_user(UserPoolId=user_pool_id, Username=username)
132+
133+
# Verify user is deleted
134+
with pytest.raises(ClientError) as exc_info:
135+
cognito_client.admin_get_user(UserPoolId=user_pool_id, Username=username)
136+
assert exc_info.value.response["Error"]["Code"] == "UserNotFoundException"
137+
138+
finally:
139+
# Clean up resources
140+
cognito_client.delete_user_pool(UserPoolId=user_pool_id)

0 commit comments

Comments
 (0)