简体   繁体   English

在 AWS SAM 中运行 pytest 不会在模板中使用环境变量。yaml

[英]Running pytest in AWS SAM doesn't use env vars in template.yaml

I'm testing my lambda with pytest.我正在用 pytest 测试我的 lambda。 My lambda, GetDevicesFunction , connects to a database using a method from a shared module, aurora , located in the utils_layer/python directory.我的 lambda GetDevicesFunction使用来自utils_layer/python目录中的共享模块aurora的方法连接到数据库。 The parameters for the database connection come from template.yaml .数据库连接的参数来自template.yaml Everything works fine when I run sam build && sam local invoke but when I run my pytest , the environment vars don't seem to get pulled in from my template.当我运行sam build && sam local invoke时一切正常,但是当我运行pytest时,似乎没有从我的模板中提取环境变量。 Is this expected or am I missing something?这是预期的还是我错过了什么?

Here is my project...这是我的项目...

# project structure

├── __init__.py
├── get_devices
│   ├── __init__.py
│   ├── app.py
│   ├── requirements.txt
├── template.yaml
├── tests
│   ├── __init__.py
│   └── unit
│       ├── __init__.py
│       └── test_handler.py
└── utils_layer
    ├── __init__.py
    ├── python
    │   ├── __init__.py
    │   ├── aurora.py
    │   ├── pg8000
# template.yaml

Globals:
  Function:
    Runtime: python3.8
    MemorySize: 256
    Timeout: 60
    Layers:
      - !Ref UtilsLayer
  Environment:
      Variables:
        DATABASE_NAME: !FindInMap [ResourcesName, !Ref MyEnvironment, databaseName]
        DATABASE_HOST: !FindInMap [ResourcesName, !Ref MyEnvironment, databaseHost]
        DATABASE_PORT: !Ref DatabasePort
        DATABASE_USER: !FindInMap [ResourcesName, !Ref MyEnvironment, databaseUser]
        DATABASE_PASSWORD: !FindInMap [ResourcesName, !Ref MyEnvironment, databasePassword]  
        ENVIRONMENT: !Ref MyEnvironment 

Mappings:
  ResourcesName:
    dev:      
      databaseHost: <db_host>
      databaseName: <db_name>
      databaseUser: <db_user>
      databasePassword: <db_password>

Parameters:
  MyEnvironment:
    Type: String
    Default: dev
    AllowedValues:
      - dev
      - staging
      - prod

Resources:
  GetDevicesFunction:
    Type: AWS::Serverless::Function
    Properties:      
      CodeUri: get_devices/
      Handler: app.lambda_handler                                                  
      Events:
        GetDevicesApiEvent:
          Type: Api
          Properties:         
            Path: /devices
            Method: GET   
            
  UtilsLayer:
    Type: AWS::Serverless::LayerVersion
    Properties:
      Description: Utils layer
      ContentUri: utils_layer/
      CompatibleRuntimes:        
        - python3.8
      RetentionPolicy: Delete 
# aurora.py

import pg8000

db_host = os.environ.get('DATABASE_HOST')
db_port = os.environ.get('DATABASE_PORT')
db_name = os.environ.get('DATABASE_NAME')
db_user = os.environ.get('DATABASE_USER')
db_password = os.environ.get('DATABASE_PASSWORD')

def make_conn():   
    conn = None
    try:                                          
        conn = pg8000.connect(
            database=db_name, 
            user=db_user, 
            password=db_password, 
            host=db_host                
            )  
    except Exception as e:
        print(f'Connection error: {e}')
    return conn
# test_handler.py

import pytest
from get_devices import app

def test_lambda_handler(apigw_event, mocker):        
    ret = app.lambda_handler(apigw_event, "")  
    data = ret['body']['data'] 
    assert ret["statusCode"] == 200    
    assert len(data) > 0 

Any suggestions on how to pull in env vars from my template would be appreciated.任何有关如何从我的模板中提取环境变量的建议都将不胜感激。

I did something like this in conftest.py :我在conftest.py中做了这样的事情:

import os
import yaml

# Read contents from template file. put all parameters out into envs
try:
    with open('template.yaml', 'rt') as handle:
        # Add constructor to handle !'s
        def any_constructor(loader, tag_suffix, node):
            if isinstance(node, yaml.MappingNode):
                return loader.construct_mapping(node)
            if isinstance(node, yaml.SequenceNode):
                return loader.construct_sequence(node)
            return loader.construct_scalar(node)
        # Add constructors
        yaml.add_multi_constructor('', any_constructor, Loader=yaml.SafeLoader)

        # Load yaml
        template = yaml.safe_load(handle)

        # Add to env
        for param in template['Parameters'].items():
            key = param[0]
            value = param[1]['Default']
            os.environ[key] = value

except yaml.YAMLError as e:
    raise ValueError(e)

You can use the same env.json intended to invoke the function locally .您可以使用相同的 env.json 来在本地调用 function In this case I use one specifically for test called test.env.json (excluded from source control in .gitignore ) with the environment parameters, with this format:在这种情况下,我使用一个专门用于测试的名为test.env.json (从.gitignore的源代码控制中排除)与环境参数,格式如下:

{
    "GetDevicesFunction": {
      "DATABASE_NAME": "dbname",
      "DATABASE_HOST": "dbhost",
      "DATABASE_PORT": "5432",
      "DATABASE_USER": "dbuser",
      "DATABASE_PASSWORD": "dbpassword",
      "ENVIRONMENT": "?"
    }
}

and use a fixture to load them:并使用夹具来加载它们:

from . import get_devices

import os
import json
import pytest


ENVIRONMENT_PATH = os.path.join(
    os.path.dirname(os.path.abspath(get_devices.__file__)),
    "../test.env.json"
)


@pytest.fixture()
def test_environ():
    """Load environment variables to mock"""
    data = {}
    with open(ENVIRONMENT_PATH) as json_file:
        data = json.load(json_file)
    for (k, v) in data["GetDevicesFunction"].items():
        os.environ[k] = str(v)
    return data


def test_lambda_handler(apigw_event, mocker, test_environ):   
    from get_devices import app
    ret = app.lambda_handler(apigw_event, "")  
    data = ret['body']['data'] 
    assert ret["statusCode"] == 200    
    assert len(data) > 0 

If you have used sam build --use-container , and your database is launched locally in a docker container bound to the default network, you can also use the test.env.json file to invoke the function locally calling:如果您使用了sam build --use-container ,并且您的数据库是在绑定到默认网络的 docker 容器中本地启动的,您还可以使用test.env.json文件在本地调用 ZC1C425268E17385D14ZA5074F:

sam local invoke GetDevicesFunction --env-vars test.env.json --docker-network docker_default --debug

and with sam build you can:使用sam build你可以:

sam local invoke GetDevicesFunction --env-vars test.env.json --debug

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 aws-sam-cli Python requirements.txt 在自定义模板时从部署的 Lambda 中丢失。yaml - aws-sam-cli Python requirements.txt missing from deployed Lambda when custom template.yaml pytest-django 在 settings.py 中使用环境变量 - pytest-django Use env vars in settings.py 由于 ModuleNotFoundError,AWS SAM 项目中的 pytest 失败 - pytest failing in AWS SAM project due to ModuleNotFoundError Django (Gunicorn) 在生产中看不到 ENV VARS,但 Django-shell 可以 - Django (Gunicorn) doesn't see ENV VARS in production but Django-shell does Unrecognized arguments YAML 运行时出错 pytest - Unrecognized arguments YAML error when running pytest 通过在 kubernetes Z6EEDC03A68A69D7C274C 文件中设置的环境变量在 python 脚本中访问的 yaml 数组的类型是什么? - What is the type of a yaml array accessed in a python script via env vars set in a kubernetes yaml file? 在python 3中使用子进程运行命令时使用ENV变量吗? - Using ENV vars while running command using subprocess in python 3? 在 AWS SAM 模板中使用现有的 S3 存储桶 - Using an existing S3 bucket in AWS SAM template pytest没有找到测试 - pytest doesn't find the test 使用 AWS SAM 创建 Hello World 应用程序:运行“sam build”时出现问题 - Creating a Hello World application using AWS SAM : issue when running "sam build"
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM