簡體   English   中英

在 AWS SAM 中運行 pytest 不會在模板中使用環境變量。yaml

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

我正在用 pytest 測試我的 lambda。 我的 lambda GetDevicesFunction使用來自utils_layer/python目錄中的共享模塊aurora的方法連接到數據庫。 數據庫連接的參數來自template.yaml 當我運行sam build && sam local invoke時一切正常,但是當我運行pytest時,似乎沒有從我的模板中提取環境變量。 這是預期的還是我錯過了什么?

這是我的項目...

# 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 

任何有關如何從我的模板中提取環境變量的建議都將不勝感激。

我在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)

您可以使用相同的 env.json 來在本地調用 function 在這種情況下,我使用一個專門用於測試的名為test.env.json (從.gitignore的源代碼控制中排除)與環境參數,格式如下:

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

並使用夾具來加載它們:

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 

如果您使用了sam build --use-container ,並且您的數據庫是在綁定到默認網絡的 docker 容器中本地啟動的,您還可以使用test.env.json文件在本地調用 ZC1C425268E17385D14ZA5074F:

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

使用sam build你可以:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM