【发布时间】:2022-01-20 16:24:56
【问题描述】:
我正在尝试为我的 lambda 处理程序编写一个测试,它使用 boto3 从存储桶下载文件并将其存储在本地:
s3_resource = boto3.resource('s3')
TEMP_FILE = '/tmp/file.csv'
def lambda_handler(event, context):
bucket_name = event['detail']['bucket']['name']
file_name = event['detail']['object']['key']
s3_resource.Bucket(bucket_name).download_file(Key=file_name, Filename=TEMP_FILE)
因为我不想在我的测试中实际与 s3 交互,所以我创建了一个虚拟 s3_upload_event 来传递给函数调用。我还使用 moto 创建了一个模拟的 s3 存储桶,并在其中放入了一些虚拟 test_data,以及一个具有 s3 权限的模拟 iam 用户:
TEST_BUCKET = "test_bucket_name"
S3_TEST_FILE_KEY = 'path/to/test.csv'
@pytest.fixture
def s3_upload_event():
return {"detail":{"bucket":{"name": TEST_BUCKET}, "object": {"key": S3_TEST_FILE_KEY}}}
@pytest.fixture
def context():
return object()
@pytest.fixture
def test_data():
return b'col_1,col_2\n1,2\n3,4\n'
@pytest.fixture
@mock_iam
def mock_user(user_name="test-user"):
# create user
client = boto3.client("iam", region_name="us-west-2")
client.create_user(UserName=user_name)
# create and attach policy
policy_document = {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["s3:*", "s3-object-lambda:*"],
"Resource": "*"
}]
}
policy_arn = client.create_policy(
PolicyName="test",
PolicyDocument=json.dumps(policy_document))["policy"]["Arn"]
client.attach_user_policy(UserName=user_name, PolicyArn=policy_arn)
# Return access keys
yield client.create_access_key(UserName=user_name)["AccessKey"]
@pytest.fixture
@mock_s3
def mock_s3(test_data, mock_user):
s3 = boto3.client(
"s3",
region_name="us-west-2",
aws_access_key_id=mock_user["AccessKeyId"],
aws_secret_access_key=mock_user["SecretAccessKey"])
s3.create_bucket(Bucket=TEST_BUCKET)
s3.put_object(Bucket=TEST_BUCKET, Key=S3_TEST_FILE_KEY, Body=test_data)
yield s3
我将这些模拟的固定装置注入到我的测试中,如下所示:
class TestLambdaHandler:
def test_lambda_handler(self, mock_user, mock_s3, s3_upload_event, context):
response = lambda_handler(event = s3_upload_event, context = context)
assert response["statusCode"] == 200
但是当我运行测试时,botocore 在到达这行代码时会抛出异常:s3_resource.Bucket(bucket_name).download_file(Key=file_name, Filename=TEMP_FILE):
botocore.exceptions.ClientError: An error occurred (403) when calling the HeadObject operation: Forbidden
当我用谷歌搜索这个错误时,这似乎与缺少 IAM 权限有关。我为模拟用户使用的 PolicyDocument 与我在代码中使用的实际策略相同,所以我不明白为什么它能够在现实生活中下载文件但在测试中失败。我的模拟用户有什么遗漏吗?
【问题讨论】:
标签: python unit-testing amazon-s3 boto3 moto