Python FAILED AssertionError with GitHub Actions CI / CD Pipeline with AWS

Question:

I am trying to reproduce, step-by-step, the instructions on this video "Cloud Resume Challenge Sprint (Sept, 2022) – Week 4" from youtube, https://youtu.be/wiyI0Ngn31o, on how to setup GitHub Actions with CD/CI pipeline for Backend testing with Python for SAM Deployment in AWS. I am using modified files from the GitHub repo of the YouTube video: https://github.com/CumulusCycles/CloudResumeChallenge/tree/main/Week_4

I have followed the video’s instructions, step-by-step; however, when I push my mail.yml file to the GitHub repository, I get the following error message from GitHub Actions:

Run pytest
============================= test session starts ==============================
platform linux -- Python 3.8.15, pytest-7.2.0, pluggy-1.0.0
rootdir: /home/runner/work/cloud-resume-challenge/cloud-resume-challenge
plugins: mock-3.10.0
collected 1 item

serverless-architecture-with-SAM/tests/test_handler.py F                 [100%]

=================================== FAILURES ===================================
_____________________________ test_lambda_handler ______________________________

    @mock.patch.dict(os.environ, {"TABLENAME": TABLENAME})
    def test_lambda_handler():
        # Check AWS creds
        assert "AWS_ACCESS_KEY_ID" in os.environ
        assert "AWS_SECRET_ACCESS_KEY" in os.environ
    
        ret = app.lambda_handler("", "")
    
        # Assert return keys
        assert "statusCode" in ret
        assert "headers" in ret
        assert "body" in ret
    
        # Check for CORS in Headers
        assert "Access-Control-Allow-Origin"  in ret["headers"]
        assert "Access-Control-Allow-Methods" in ret["headers"]
        assert "Access-Control-Allow-Headers" in ret["headers"]
    
        # Check status code
        if ret["statusCode"] == 200:
>           assert "visit_count" in ret["body"]
E           AssertionError: assert 'visit_count' in '39'

serverless-architecture-with-SAM/tests/test_handler.py:34: AssertionError
=========================== short test summary info ============================
FAILED serverless-architecture-with-SAM/tests/test_handler.py::test_lambda_handler - AssertionError: assert 'visit_count' in '39'
============================== 1 failed in 0.53s ===============================
Error: Process completed with exit code 1.

Here are the contents of my test_handler.py file that referenced in the error:

import os
import re
import json

from unittest import mock

from hello_world import app

#os.environ['AWS_DEFAULT_REGION'] = 'us-east-1'

with open('serverless-architecture-with-SAM/template.yaml', 'r') as f:
    TABLENAME = re.search(r'TableName: (.*)?', f.read()).group(1)

@mock.patch.dict(os.environ, {"TABLENAME": TABLENAME})
def test_lambda_handler():
    # Check AWS creds
    assert "AWS_ACCESS_KEY_ID" in os.environ
    assert "AWS_SECRET_ACCESS_KEY" in os.environ

    ret = app.lambda_handler("", "")

    # Assert return keys
    assert "statusCode" in ret
    assert "headers" in ret
    assert "body" in ret

    # Check for CORS in Headers
    assert "Access-Control-Allow-Origin"  in ret["headers"]
    assert "Access-Control-Allow-Methods" in ret["headers"]
    assert "Access-Control-Allow-Headers" in ret["headers"]

    # Check status code
    if ret["statusCode"] == 200:
        assert "visit_count" in ret["body"]
        assert json.loads(ret["body"])["visit_count"].isnumeric()
    else:
        assert json.loads(ret["body"])["visit_count"] == -1

    return

And the contents of my app.py file:

import json
import boto3

dynamodb = boto3.resource('dynamodb', region_name="us-east-1")

table = dynamodb.Table('resume-website-app-tbl')

def lambda_handler(event, context):
    response = table.get_item(
        Key = {
            'ID':'visits'
        }
    )
    
    visit_count = response['Item']['counter'] 
    visit_count = str(int(visit_count) + 1)
    
    response = table.put_item(
        Item = {
            'ID':'visits',
            'counter': visit_count
        }
    )

    return {
        'statusCode': 200,
        'headers': {
            'Access-Control-Allow-Headers': '*',
            'Access-Control-Allow-Origin': '*',
            'Access-Control-Allow-Methods': '*'
        },
        'body': visit_count
    }

Here is a copy of my main.yml file:

name: main
on: push


jobs:
  test-infra:
    runs-on: ubuntu-latest
    timeout-minutes: 2
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-python@v3
        with:
          python-version: 3.8
      - name: Install dependencies
        run: |
          cd serverless-architecture-with-SAM/tests
          python -m pip install --upgrade pip
          pip install -r requirements.txt
      - name: Run tests with pytest
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_DEFAULT_REGION: us-east-1
        run: pytest

  build-and-deploy-infra:
    needs: test-infra
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-python@v2
      - uses: aws-actions/setup-sam@v1
      - uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1
      - run: sam build
        working-directory: serverless-architecture-with-SAM
      - run: sam deploy --no-confirm-changeset --no-fail-on-empty-changeset
        working-directory: serverless-architecture-with-SAM

  deploy-site:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: jakejarvis/s3-sync-action@master
        with:
          args: --delete
        env:
          AWS_S3_BUCKET: justinhenson-cloud-resume-website
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          SOURCE_DIR: serverless-architecture-with-SAM/resume-site

I am completely lost as to why the assert is failing. Any help is greatly appreciated.

Asked By: Justin Henson

||

Answers:

assert "visit_count" in ret["body"]

You’re asserting that your body has a key called "visit_count", but

'body': visit_count

your actual body ist just a plain integer. Did you mean something like

'body': {
    'visit_count' : visit_count
}

?

Answered By: Sören